package com.billionsfinance.hessian.common.machine;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;


/**
 * 分布式环境中的每一个服务资源该如何处理
 *
 * @ ClassName: MachineResource.java
 * @ Author: WeiHui-Z
 * @ Date: 2016/11/24 11:07
 * @ Version: v1.0.0
 */
public final class MachineResource {

	private Logger LOGGER = LoggerFactory.getLogger(MachineResource.class);

	/**
	 * 偏移值
	 */
	private static final Long LongValue = (long) (0 - Integer.MIN_VALUE);

	/**
	 * 读写锁
	 */
	private ReadWriteLock lock = new ReentrantReadWriteLock();

	/**
	 * k-服务名字,v-提供服务的机器列表
	 */
	private Map<String, List<String>> serviceList = new HashMap<>();
	/**
	 * k-服务名称,v--服务列表索引，下一次使用哪台机器上的服务
	 */
	private Map<String, AtomicInteger> serviceIndex = new HashMap<>();

	/**
	 * 构造方法私有化
	 */
	private MachineResource() {

	}

	private static class InstanceHolder {

		private static MachineResource INSTANCE = new MachineResource();
	}

	/**
	 * 采用静态内部类的单例模式
	 */
	public static MachineResource getInstance() {
		return InstanceHolder.INSTANCE;
	}

	/**
	 * 增加服务--启动时增加服务信息
	 *
	 * @param service-服务
	 * @param provider-服务提供方
	 */
	public void addMachineResource(String service, String provider) {
		try {
			lock.writeLock().lock();
			List<String> providerList = serviceList.get(service);
			if (providerList == null || providerList.isEmpty()) {
				//第一次加载服务
				providerList = new ArrayList<>();
				// 建立下标,下标是指下一个要拿的机器的序号，以-1开始
				serviceIndex.put(service, new AtomicInteger(-1));
			}
			providerList.add(provider);
			serviceList.put(service, providerList);
		} finally {
			lock.writeLock().unlock();
		}
	}

	/**
	 * 删除服务
	 *
	 * @param service
	 * @param provider
	 */
	public void removeMachineResource(String service, String provider) {
		try {
			lock.writeLock().lock();
			List<String> providerList = serviceList.get(service);
			if (providerList != null) {
				// 先删除机器
				providerList.remove(provider);
				// 如果列表为空，也删除列表和下标--服务下线
				if (providerList.isEmpty()) {
					serviceList.remove(service);
					serviceIndex.remove(service);
				}
			}
		} finally {
			lock.writeLock().unlock();
		}
	}

	public String getResource(String service) {
		String provider = null;
		try {
			// 获取锁
			lock.readLock().lock();
			// 拿取机器列表
			List<String> machineList = serviceList.get(service);
			if (null == machineList) {
				throw new Exception("no machineList found for :" + service);
			}
			// 计算机器下标
			AtomicInteger index = serviceIndex.get(service);
			int newIndex = index.incrementAndGet();// [-2147483648,
			// 修正
			if (newIndex < 0) {// 务必要进行修正// 最大值的话，就要重新开始,否则会成为负数
				newIndex = (int) ((long) newIndex + LongValue);
			}
			// 应用
			newIndex = newIndex % machineList.size();
			// 拿取目标machine
			provider = machineList.get(newIndex);
		} catch (Exception e) {
			LOGGER.error("获取[{}]服务时出现了一个错误.", service, e);
		} finally {// 释放锁
			lock.readLock().unlock();
		}
		return provider;
	}

	/**
	 * 导出服务详细信息列表
	 *
	 * @return
	 */
	public Map<String, List<String>> getServicesDetail() {
		Map<String, List<String>> result = new HashMap<>();
		Set<Map.Entry<String, List<String>>> entries = serviceList.entrySet();
		for (Map.Entry<String, List<String>> entry : entries) {
			String key = entry.getKey();
			List<String> value = entry.getValue();
			List<String> list = new ArrayList<>();
			for (String s : value) {
				list.add(s);
			}
			result.put(key, list);
		}
		return result;
	}

}